﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;

namespace Ymatou.ServiceCenter.Common
{
    public static class ListExtensions
    {

        public static void AddUnqiue<T>(this IList<T> list, T item)
        {
            if (!list.Contains(item))
            {
                list.Add(item);
            }
        }

        public static bool InsertUnqiue<T>(this IList<T> list, int index, T item)
        {
            if (list.Contains(item) == false)
            {
                list.Insert(index, item);
                return true;
            }
            return false;
        }

        public static int InsertRangeUnique<T>(this IList<T> list, int startIndex, IEnumerable<T> items)
        {
            var index = startIndex + items.Count(item => list.InsertUnqiue(startIndex, item));
            return (index - startIndex);
        }

        public static int IndexOf<T>(this IList<T> list, Func<T, bool> comparison)
        {
            for (var i = 0; i < list.Count; i++)
            {
                if (comparison(list[i]))
                    return i;
            }
            return -1;
        }

        public static string Join<T>(this IList<T> list, char joinChar)
        {
            return list.Join(joinChar.ToString());
        }

        public static string Join<T>(this IList<T> list, string joinString)
        {
            StringBuilder result = new StringBuilder();

            int listCount = list.Count;
            int listCountMinusOne = listCount - 1;

            if (list != null && listCount > 0)
            {
                if (listCount > 1)
                {
                    for (var i = 0; i < listCount; i++)
                    {
                        if (i != listCountMinusOne)
                        {
                            result.Append(list[i]);
                            result.Append(joinString);
                        }
                        else
                            result.Append(list[i]);
                    }
                }
                else
                    result.Append(list[0]);
            }

            return result.ToString();
        }

        public static List<T> Cast<T>(this IList source)
        {
            var list = new List<T>();
            list.AddRange(source.OfType<T>());
            return list;
        }

        #region Merge

        public static List<T> Merge<T>(params List<T>[] lists)
        {
            var merged = new List<T>();
            foreach (var list in lists) merged.Merge(list);
            return merged;
        }

        public static List<T> Merge<T>(Expression<Func<T, object>> match, params List<T>[] lists)
        {
            var merged = new List<T>();
            foreach (var list in lists) merged.Merge(list, match);
            return merged;
        }

        public static List<T> Merge<T>(this List<T> list1, List<T> list2, Expression<Func<T, object>> match)
        {
            if (list1 != null && list2 != null && match != null)
            {
                var matchFunc = match.Compile();
                foreach (var item in list2)
                {
                    var key = matchFunc(item);
                    if (!list1.Exists(i => matchFunc(i).Equals(key))) list1.Add(item);
                }
            }

            return list1;
        }

        public static List<T> Merge<T>(this List<T> list1, List<T> list2)
        {
            if (list1 != null && list2 != null) foreach (var item in list2.Where(item => !list1.Contains(item))) list1.Add(item);
            return list1;
        }

        public static T RandomOne<T>(this IList<T> list)
        {
            if (list == null)
                return default(T);
            int index = Math.Abs(Guid.NewGuid().GetHashCode()) % list.Count;
            return list[index];
        }

        public static object RandomOne(this IList list)
        {
            if (list == null)
                return null;
            int index = Math.Abs(Guid.NewGuid().GetHashCode()) % list.Count;
            return list[index];
        }

        public static IList<T> Paging<T>(this IList<T> list, int pageSize, int pageIndex)
        {
            if (list == null)
                return null;

            var skipNum = 0;
            var takeNum = pageSize;
            if (list.Count <= pageSize)
            {
                takeNum = list.Count;
            }
            else
            {
                skipNum = pageSize * (pageIndex - 1);
            }

            return list.Skip(skipNum).Take(takeNum).ToList<T>();

        }


        public static IList<string> PrefixWith(this IList<string> items, string prefix)
        {
            for (int ndx = 0; ndx < items.Count; ndx++)
            {
                items[ndx] = string.Concat(prefix, items[ndx]);
            }
            return items;
        }
        #endregion
    }
}
